////////////////////////////////////////////////////////////////////////////////
//
//	This file is part of Woozox, see <http://code.google.com/p/woozox/>.
//
//	Copyright 2008-2009 Florian David
//
//	Woozoo is free software: you can redistribute it and/or modify
//	it under the terms of the GNU Lesser General Public License as 
//	published by the Free Software Foundation, either version 3 of 
//	the License, or (at your option) any later version.
//
//	Woozoo is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU Lesser General Public 
//	License along with Woozoo. If not, see <http://www.gnu.org/licenses/>.
//
////////////////////////////////////////////////////////////////////////////////
package org.woozoo.xhtml.wordpress  
{ 
	import org.woozoo.xhtml.core.base.*;
	import org.woozoo.xhtml.extended.EXAPI;
	import org.woozoo.xhtml.wordpress.base.*;
	import org.woozoo.xhtml.wordpress.constant.WPConst;
	import org.woozoo.xhtml.wordpress.event.WPCommentEvent;
	import org.woozoo.xhtml.wordpress.theme.*;
	  
	/**  
	 * This class will give you all the access to the main method of the Woozox
	 * */
	public class WPAPI extends EXAPI
	{
		private static var __instance : WPAPI;		
		
		private var __blogTitle : String;
		private var __blogDescription : String;
		
		/**
		 * The theme used by your blog and therefor by the api.
		 * 
		 * <p>The theme defines static var that are used to parse your documents.</p>
		 * */
		public var theme : WPTheme;

		/**
		 * Singleton getter
		 * 
		 * @return The singleton
		 * */
		public static function getInstance() : WPAPI {
			if (!__instance) {
				_instanciable = true;
				__instance = new WPAPI();
				_instanciable = false;
			}
			return __instance;
		}
		
		/**
		 * @private
		 * */
		public function WPAPI() : void {
			defaultDocumentClass = WPDocument;
			defaultCategoryClass = WPCategory;
			_construct();
		}
		
		override protected function _loadDocumentComplete(document:Document, successCallBack:Function, errorCallBack:Function):void {
			if (!theme) {
				trace('You should set the theme before setuping your api. We set the theme to WPDefaultTheme');
				theme = new WPDefaultTheme();
			}
			__createCategories();
			__createArchives();
			__createPages();
			__createTags();
			super._loadDocumentComplete(document, successCallBack, errorCallBack);
		}
		
		/**
		 * Return the blog title
		 * 
		 * @return The blog title
		 * */
		public function get blogTitle() : String {
			if (!__blogTitle) {
				__blogTitle = (getDocumentIndex().$$(WPTheme.BLOG_TITLE_SELECTOR)[0] as Element).innerHTML;
			}
			return __blogTitle;
		}
		
		/**
		 * Return the blog description
		 * 
		 * @return The blog description
		 * */
		public function get blogDescription() : String {
			if (!__blogDescription) {
				__blogDescription = (getDocumentIndex().$$(WPTheme.BLOG_DESCRIPTION_SELECTOR)[0] as Element).innerHTML;
			}
			return __blogDescription;		
		}
		
		/**
		 * Will return the list of posts that are on the document.
		 * 
		 * <p>It will also add each post to the list of available document you can get throw API.getDocumentByName.</p>
		 * 
		 * @return The list of WPPost
		 * */
		public function getPosts(document : Document) : Array /* of WPPost */ {
			var res : Array = [];
			var list : Array = document.$$(WPTheme.BLOG_POSTS_SELECTOR);
			var len : int = list.length; 
			for (var i : int = 0; i < len; i++) {
				var element : Element = list[i];
				var firstA : Element = element.getElementsByTagName('a', -1, 1)[0];
				
				var name : String = "";
				var url : String = "";
				if (firstA) {
					name = firstA.innerHTML;
					url = firstA.att('href');
				} else {
					var h2 : Element = element.getElementsByTagName('h2', -1, 1)[0];
					name = h2.innerHTML;
					url = document.url;
				}				
				var post : WPPost = getDocumentByName(name) as WPPost;
				if (!post){
					post = new WPPost(name, url, element);
				}
				addDocument(post); 
				res.push(post);
			}
			return res;
		}
		
		/**
		 * Permit you to send a comment to your wordpress blog.
		 * 
		 * <p>The successCallBack method signature has to be :<br />
		 * function successCallBack(post : WPPost, comment : WPComment) : void</code>.
		 * </p>
		 * 
		 * <p>The errorCallBack method signature has to be :<br />
		 * <code>function errorCallBack(reason : WPCommentErrorReason, post : WPPost, comment : WPComment) : void</code>.<br />
		 * The param reason will tell you the reason why it failed.
		 * </p>
		 * 
		 * @param post The post to add the comment on 
		 * @param content The content of the comment
		 * @param commenterPseudo The pseudo of the commenter
		 * @param commenterEmail The email of the commenter
		 * @param successCallBack If sending the comment success, this methid will be called
		 * @param errorCallBack If sending the comment fail, this method will be called
		 * @param commenterWebsite The website of the commenter
		 * */
		public function sendComment(post : WPPost, content : String, commenterPseudo : String, commenterEmail : String, successCallBack : Function, errorCallBack : Function = null, commenterWebsite : String = "") : void {
			var comment : WPComment = post.sendComment(content, commenterPseudo, commenterEmail, commenterWebsite);
			if (comment) {
				post.addEventListener(WPCommentEvent.COMMENT_SUCCEED, function(e : WPCommentEvent) : void {
					successCallBack(post, comment);
				});
				if (errorCallBack != null) {
					post.addEventListener(WPCommentEvent.COMMENT_FAILED, function(e : WPCommentEvent) : void {
						errorCallBack(e.reason, post, comment);
					});
				}
			} else {
				errorCallBack(new WPCommentErrorReason(WPCommentErrorReason.COMMENT_NOT_VALID), post, comment);
			}
		}
		
		/**
		 * Permit you to search on your WordPress blog.
		 * 
		 * <p>The successCallBack method signature has to be :<br />
		 * function successCallBack(search : String, wpPosts : Array) : void</code>.
		 * </p>
		 * 
		 * <p>The errorCallBack method signature has to be :<br />
		 * <code>function errorCallBack(reason : DocumentErrorReason, search : String) : void</code>.<br />
		 * The param reason will tell you the reason why it failed.
		 * </p>
		 * 
		 * @param search The value to search for
		 * @successCallBack If the search succeed, this method will be called
		 * @errorCallBack If the search failed for any reason, this method will be called
		 * */
		public function search(search : String, successCallBack : Function, errorCallBack : Function = null) : void {
			var searchSuccessCallBack : Function = function(document : Document) : void {
				successCallBack(search, document);
			}
			var searchErrorCallBack : Function = function(document : Document, reason : DocumentErrorReason) : void {
				errorCallBack(reason, search);
			}
			
			var document : Document = getDocumentByName('Search ('+search+')');
			if (!document) {
				document = new defaultDocumentClass('Search ('+search+')', getDocumentIndex().url + WPConst.SEARCH_URL.replace('{0}', search));
				addDocument(document);
			} 
			loadDocument(document, searchSuccessCallBack, searchErrorCallBack);
		}
		
		public function loadArchivePost(index : int, successCallBack : Function, errorCallBack : Function) : void {
			var url : String = getDocumentIndex().url;
			if (index >= 1) {
				url += WPConst.ARCHIVE_PAGE_URL.replace('{0}', index);
			}
			var document : Document = getDocumentByName('Entries (page '+index+')');
			if (!document) {
				document = new defaultDocumentClass('Entries (page '+index+')', url);
				addDocument(document);
			} 
			loadDocument(document, successCallBack, errorCallBack);
		} 
		
		//////////////////////
		// CREATE CATEGORIES
		//////////////////////
		
		private function __createCategories() : void {
			var list : Array = getDocumentIndex().$$(WPTheme.BLOG_CATEGORIES_SELECTOR);
			var parent : Category = new Category(WPTheme.BLOG_CATEGORIES_NAME);
			_documentManager.addCategory(parent);
			parent.addSubCategories(__createCategoriesRecurse(list, parent));
		}
		
		private function __createCategoriesRecurse(list : Array, parent : Category) : Array /* of Category */ {
			var res : Array = [];
			var len : int = list.length;
			for (var i : int = 0; i < len; i++) {
				var li : Element = list[i];
				var a : Element = li.firstChild;
				var category : WPCategory = new WPCategory(a.innerHTML);
				var categoryDocument : WPDocument = new WPDocument(a.innerHTML, a.att('href'), a);
				category.document = categoryDocument;
				category.parent = parent;
				
				var ul : Element = li.getElementsByTagName('ul', 1)[0];
				if (ul) {
					var liList : Array = ul.getElementsByTagName('li', 1);
					category.addSubCategories(__createCategoriesRecurse(liList, category));
				}
				_documentManager.addCategory(category);
				res.push(category);
			}
			return res; 
		}
		
		////////////////////// 
		// CREATE ARCHIVES
		//////////////////////
		
		private function __createArchives() : void {
			__createDocumentsFromSelectorAndCategory(WPTheme.BLOG_ARCHIVES_SELECTOR, WPTheme.BLOG_ARCHIVES_NAME, WPArchive);
		}
		
		//////////////////////
		// CREATE TAGS
		//////////////////////
		
		private function __createTags() : void {
			if (!WPTheme.BLOG_HAS_TAGS) return;
			__createDocumentsFromSelectorAndCategory(WPTheme.BLOG_TAGS_SELECTOR, WPTheme.BLOG_TAGS_NAME, WPTag);
		}

		//////////////////////
		// CREATE PAGES
		//////////////////////
		
		private function __createPages() : void {
			if (!WPTheme.BLOG_HAS_PAGES) return;
			__createDocumentsFromSelectorAndCategory(WPTheme.BLOG_PAGES_SELECTOR, WPTheme.BLOG_PAGES_NAME, WPPage);
		}
		
		//////////////////////
		// CREATE
		//////////////////////
		
		private function __createDocumentsFromSelectorAndCategory(selector : String, categoryName : String, klass : Class) : void {
			var category : Category = new Category(categoryName);
			_documentManager.addCategory(category);
			
			var list : Array = getDocumentIndex().$$(selector);
			var len : int = list.length;
			for (var i : int = 0; i < len; i++) {
				var a : Element = list[i];
				var page : Document = new klass(a.innerHTML, a.att('href'), a);
				page.addCategory(category);
				addDocument(page);
			}
		}
	}
}